package com.bizmda.bizsip.app.executor.script;

import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.bizmda.bizsip.app.service.AppClientService;
import com.bizmda.bizsip.common.*;
import com.bizmda.bizsip.config.AbstractSinkConfig;
import com.bizmda.bizsip.config.RabbitmqSinkConfig;
import com.bizmda.bizsip.config.RestSinkConfig;
import com.bizmda.bizsip.config.SinkConfigMapping;
import com.open.capacity.redis.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.web.client.RestTemplate;
import org.ssssssss.magicapi.config.MagicModule;
import org.ssssssss.script.annotation.Comment;

import java.util.HashMap;
import java.util.Map;

import static com.bizmda.bizsip.app.service.AppClientService.PREFIX_SIP_ASYNCLOG;

/**
 * @author 史正烨
 */
@Slf4j
public class SipFunctions implements MagicModule {

    private static SinkConfigMapping sinkConfigMapping = null;
    private static RestTemplate restTemplate = null;
    //    private static TmService tmService = null;
    private static AppClientService appClientService = null;
    private static RabbitTemplate rabbitTemplate = null;
    private static RedisUtil redisUtil = null;

    @Comment("执行适配器服务调用")
    public static BizMessage<JSONObject> callSink(@Comment("服务ID") String sinkId, @Comment("调用输入参数") Object inData) {
        log.debug("入参:{},{}", sinkId, inData);
        JSONObject jsonObject = JSONUtil.parseObj(inData);
        if (restTemplate == null) {
            restTemplate = SpringUtil.getBean(RestTemplate.class);
        }
        if (sinkConfigMapping == null) {
            sinkConfigMapping = SpringUtil.getBean(SinkConfigMapping.class);
        }

        BizMessage<JSONObject> inMessage = BizTools.bizMessageThreadLocal.get();
        inMessage.setData(jsonObject);

        AbstractSinkConfig sinkConfig = (AbstractSinkConfig) sinkConfigMapping.getSinkConfig(sinkId);
        BizMessage<JSONObject> outMessage = null;
        if (sinkConfig.getType() == AbstractSinkConfig.TYPE_REST) {
            RestSinkConfig restServerAdaptorConfig = (RestSinkConfig) sinkConfig;
            log.debug("调用Restful服务:{}", restServerAdaptorConfig.getUrl());
            log.trace("Rest请求:\n{}", BizUtils.buildBizMessageLog(inMessage));
            outMessage = restTemplate.postForObject(restServerAdaptorConfig.getUrl(), inMessage, BizMessage.class);
        } else if (sinkConfig.getType() == AbstractSinkConfig.TYPE_RABBITMQ) {
            RabbitmqSinkConfig rabbitmqSinkConfig = (RabbitmqSinkConfig) sinkConfig;
            log.debug("调用RabbitMQ服务:exchange[{}],route-key[{}]",
                    rabbitmqSinkConfig.getExchange(), rabbitmqSinkConfig.getRoutingKey());
            if (rabbitTemplate == null) {
                rabbitTemplate = SpringUtil.getBean(RabbitTemplate.class);
            }
            rabbitTemplate.convertAndSend(rabbitmqSinkConfig.getExchange(),
                    rabbitmqSinkConfig.getRoutingKey(), inMessage);
            return BizMessage.buildSuccessMessage(inMessage, new JSONObject());
        } else {
            log.error("未知的Sink类型:" + sinkConfig.getType());
            return null;
        }
        if (!(outMessage.getData() instanceof JSONObject)) {
            outMessage.setData(JSONUtil.parseObj(outMessage.getData()));
        }
        log.debug("返回:\n{}", BizUtils.buildBizMessageLog(outMessage));
        return outMessage;
    }

    @Comment("执行SAF服务调用")
    public static BizMessage<JSONObject> doDelayService(@Comment("服务ID") String serviceId, @Comment("调用输入参数") Object inData, @Comment("延迟毫秒数") String millisecondStr) {
        log.debug("入参:{},{},{}", serviceId, inData, millisecondStr);
        if (appClientService == null) {
            appClientService = SpringUtil.getBean(AppClientService.class);
        }
        JSONObject jsonObject = JSONUtil.parseObj(inData);

        BizMessage<JSONObject> inMessage = BizTools.bizMessageThreadLocal.get();
        inMessage.setData(jsonObject);

        String[] millisecondStrArray = millisecondStr.split(",");
        int[] milliseconds = new int[millisecondStrArray.length];
        for (int i = 0; i < millisecondStrArray.length; i++) {
            milliseconds[i] = Integer.parseInt(millisecondStrArray[i]);
        }
        BizMessage<JSONObject> outMessage = appClientService.callDelayAppService(serviceId, inData, milliseconds);
        log.debug("返回:\n{}", BizUtils.buildBizMessageLog(outMessage));
        return outMessage;
    }

//    @Comment("执行RabbitMQ RPC服务调用")
//    public static BizMessage<JSONObject> callRabbitMQ(@Comment("队列名") String queueName,@Comment("调用输入参数") Object inData) {
//        log.debug("sip.callRabbitMQ({}),\n{}",queueName,BizUtils.buildJsonLog(inData));
//
//        JSONObject jsonObject = JSONUtil.parseObj(inData);
//
//        BizMessage<JSONObject> inMessage = BizUtils.bizMessageThreadLocal.get();
//        inMessage.setData(jsonObject);
//        CorrelationData correlationData = new CorrelationData(inMessage.getTraceId());
//        if (rabbitTemplate == null) {
//            rabbitTemplate = SpringUtil.getBean("rabbitTemplate");
//        }
//
//        Object response = rabbitTemplate.convertSendAndReceive("directExchange", queueName, inMessage, correlationData);
//        log.debug("sip.callRabbitMQ()返回:\n{}",BizUtils.buildBizMessageLog((BizMessage<JSONObject>)response));
//        return (BizMessage<JSONObject>)response;
//    }

//    @Comment("设置SAF服务的延迟执行时间")
//    public static void setTmDelayTime(@Comment("延迟执行时间") int delayTime) {
//        TmContext tmContext = BizUtils.tmContextThreadLocal.get();
//        tmContext.setDelayTime(delayTime);
//        BizUtils.tmContextThreadLocal.set(tmContext);
//    }
//
//    @Comment("获取SAF服务的延迟执行时间")
//    public static int getTmDelayTime() {
//        TmContext tmContext = BizUtils.tmContextThreadLocal.get();
//        return tmContext.getDelayTime();
//    }

    @Comment("获取SAF服务的当前重试次数")
    public static int getServiceRetryCount() {
        TmContext tmContext = BizTools.tmContextThreadLocal.get();
        log.debug("返回:{}", tmContext.getRetryCount());
        return tmContext.getRetryCount();
    }

    @Comment("保存异步服务上下文")
    public void saveAsyncContext(@Comment("全局交易索引键") String transactionKey, @Comment("异步上下文变量") Object context, @Comment("异步服务超时时间") long timeout) {
        log.debug("入参:{},{},{}", transactionKey, timeout, context);
        BizMessage bizMessage = BizTools.bizMessageThreadLocal.get();
        Map<String, Object> map = new HashMap<>(16);
        map.put("traceId", bizMessage.getTraceId());
        map.put("context", context);
        if (redisUtil == null) {
            redisUtil = SpringUtil.getBean(RedisUtil.class);
        }
        redisUtil.set(PREFIX_SIP_ASYNCLOG + transactionKey, context, timeout);
    }

    /**
     * 恢复异步服务上下文
     *
     * @param transactionKey 异步回调的全局唯一交易索引键
     * @return 异步服务上下文
     */
    @Comment("恢复异步服务上下文")
    public Object loadAsyncContext(@Comment("全局交易索引键") String transactionKey) {
        log.debug("入参:{}", transactionKey);
        if (redisUtil == null) {
            redisUtil = SpringUtil.getBean(RedisUtil.class);
        }
        Map<String, Object> map = (Map<String, Object>) redisUtil.get(PREFIX_SIP_ASYNCLOG + transactionKey);
        if (map == null) {
            return null;
        }
        String traceId = (String) map.get("traceId");
        Object context = map.get("context");
        BizMessage bizMessage = BizTools.bizMessageThreadLocal.get();
        if (bizMessage.getParentTraceId() == null) {
            log.debug("重置parentTraceId:{}", traceId);
            bizMessage.setParentTraceId(traceId);
            BizTools.bizMessageThreadLocal.set(bizMessage);
            log.debug("返回:{}", context);
            return context;
        } else if (bizMessage.getParentTraceId() == traceId) {
            log.debug("返回:{}", context);
            return context;
        } else {
//            throw new BizException(BizResultEnum.ASYNC_SERVICE_PARENT_TRANCTION_BINDDING_EOORO);
            log.debug("返回:{}", context);
            return context;
        }
    }
//    @Comment("设置当前SAF服务的运行状态")
//    public static void setServiceStatus(@Comment("SAF服务运行状态") String status) {
//        TmContext tmContext = BizUtils.tmContextThreadLocal.get();
//        if (tmContext == null) {
//            return;
//        }
//        if ("success".equalsIgnoreCase(status)) {
//            tmContext.setServiceStatus(TmContext.SERVICE_STATUS_SUCCESS);
//        }
//        else if("error".equalsIgnoreCase(status)) {
//            tmContext.setServiceStatus(TmContext.SERVICE_STATUS_ERROR);
//        }
//        else if("retry".equalsIgnoreCase(status)) {
//            tmContext.setServiceStatus(TmContext.SERVICE_STATUS_RETRY);
//        }
//        BizUtils.tmContextThreadLocal.set(tmContext);
//    }

    @Comment("构建返回错误信息")
    public static ExecutorError error(String message) {
        log.debug("入参:{}", message);
        ExecutorError error = new ExecutorError();
        error.setMessage(message);
        error.setTimeoutException(false);
        return error;
    }

    @Comment("构建返回错误信息")
    public static ExecutorError timeout() {
//        BizUtils.debug("入参",message);
        ExecutorError error = new ExecutorError();
//        error.setMessage(message);
        error.setTimeoutException(true);
        return error;
    }

    @Override
    public String getModuleName() {
        return "sip";
    }
}
